<template>
  <el-dialog v-model="dialogShow" :title="dialog.title" width="1100px" @close="handleCloseDialog()">
    <div v-loading="dialog.loading">
      <el-form ref="flowFormRef" :model="formData" :rules="rules" label-position="top">
        <el-form-item label="流程名称" prop="name">
          <el-input v-model="formData.name" placeholder="请输入流程名称"></el-input>
        </el-form-item>

        <el-form-item label="描述" prop="remark">
          <el-input
            type="textarea"
            v-model="formData.remark"
            placeholder="请输入流程描述"
          ></el-input>
        </el-form-item>
      </el-form>

      <el-table :data="formData.flowNodes" stripe class="data-table__content" height="260">
        <el-table-column type="index" width="50" align="center" />
        <el-table-column label="节点名称" prop="name" width="140">
          <template #default="scope">
            <el-input v-model="scope.row.name" placeholder="请输入节点名称"></el-input>
          </template>
        </el-table-column>
        <el-table-column label="描述" prop="remark" width="220">
          <template #default="scope">
            <el-input v-model="scope.row.remark" placeholder="请输入节点描述"></el-input>
          </template>
        </el-table-column>
        <el-table-column label="节点类型" prop="nodeType" width="100">
          <template #default="scope">
            <el-select
              v-model="scope.row.nodeType"
              placeholder="请选择"
              @change="handleChangeNodeType(scope.row)"
            >
              <el-option
                v-for="item in Object.keys(FLOW_NODE_TYPE_LABEL)"
                :key="item"
                :label="FLOW_NODE_TYPE_LABEL[item]"
                :value="item"
              />
            </el-select>
          </template>
        </el-table-column>
        <el-table-column label="审核方式">
          <template #default="scope">
            <el-select
              v-if="scope.row.nodeType == FlowNodeType.AUDITOR_NODE"
              v-model="scope.row.auditorType"
              placeholder="选择审核类型"
            >
              <el-option
                v-for="item in Object.keys(FLOW_AUDIT_TYPE_LABEL)"
                :key="item"
                :label="FLOW_AUDIT_TYPE_LABEL[item]"
                :value="item"
              />
            </el-select>
          </template>
        </el-table-column>
        <el-table-column label="审核不通过回退">
          <template #default="scope">
            <el-select
              v-if="scope.$index > 0 && scope.row.nodeType == FlowNodeType.AUDITOR_NODE"
              v-model="scope.row.backNodeId"
              placeholder="选择回退节点"
            >
              <el-option
                v-for="(nd, nIdx) in getBackNodeList(scope)"
                :key="nIdx"
                :label="`${nIdx + 1}. ${nd.name}`"
                :value="nd.sort.toString()"
              />
            </el-select>
          </template>
        </el-table-column>
        <el-table-column label="操作" fixed="right" width="170" align="center">
          <template #default="scope">
            <el-button size="small" type="primary" link @click="handleAddTask(scope)">
              添加
            </el-button>
            <el-button
              size="small"
              link
              :disabled="scope.$index === 0"
              @click="handleMoveUp(scope)"
            >
              上移
            </el-button>
            <el-button
              size="small"
              link
              :disabled="scope.$index == formData.flowNodes.length - 1"
              @click="handleMoveDown(scope)"
            >
              下移
            </el-button>
            <el-button size="small" type="danger" link @click="handleDelete(scope)">删除</el-button>
          </template>
        </el-table-column>
      </el-table>
    </div>
    <template #footer>
      <div class="dialog-footer">
        <el-button type="primary" @click="handleSubmit">确 定</el-button>
        <el-button @click="handleCloseDialog()">取 消</el-button>
      </div>
    </template>
  </el-dialog>
</template>

<script lang="ts" setup>
import FlowAPI, { FlowForm, FlowPageVO } from "@/api/flow/flow.api";
import FlowNodeAPI, {
  FLOW_AUDIT_TYPE_LABEL,
  FLOW_NODE_TYPE_LABEL,
  FlowAuditorType,
  FlowNodeType,
  FlowNodeVo,
} from "@/api/flow/flowNode.api";
import { toMap } from "@/utils";
import { cloneDeep } from "lodash-es";

const props = defineProps<{
  visible: boolean;
  data?: FlowPageVO;
}>();
const emits = defineEmits<{
  (e: "dialogClose", id?: string): void;
}>();

const dialog = reactive({
  title: "",
  loading: false,
});
// 处理props的数据 重新定义 dialogVisible
const dialogShow = computed({
  get() {
    return props.visible;
  },
  set(val) {
    return val;
  },
});

const flowFormRef = ref();
const defaultForm = {
  id: "",
  name: "",
  remark: "",
  flowNodes: [],
};
const defaultNodeForm: FlowNodeVo = {
  id: "",
  name: "",
  remark: "",
  auditorType: null,
  nodeType: FlowNodeType.BUSINESS_NODE,
  backNodeId: undefined,
  sort: 0,
};
const rules = reactive({
  name: [{ required: true, message: "请输入流程名称", trigger: "blur" }],
});
const formData = reactive<FlowForm>(cloneDeep(defaultForm));

watch(
  () => props.visible,
  (val) => {
    if (val) {
      dialog.title = props.data ? "修改流程" : "新增流程";
      loadFlowDetail();
    }
  },
  {
    immediate: true,
  }
);

/**
 * 加载详情
 */
const loadFlowDetail = () => {
  if (!props.data) {
    formData.flowNodes = [cloneDeep(defaultNodeForm)];
    return;
  }
  Object.assign(formData, props.data);
  dialog.loading = true;
  FlowNodeAPI.getNodes(props.data.id)
    .then((data) => {
      const backIdSortMap = toMap(data, "id", "sort"); //id对照的sort
      formData.flowNodes = data.map((d) => {
        if (d.backNodeId) {
          d.backNodeId = backIdSortMap[d.backNodeId]?.toString() || "";
        }
        return d;
      });
    })
    .finally(() => {
      dialog.loading = false;
    });
};

// 改变节点类型
function handleChangeNodeType(row: FlowNodeVo) {
  if (row.nodeType == FlowNodeType.AUDITOR_NODE) {
    row.auditorType = FlowAuditorType.ALL_PASS;
  } else {
    row.auditorType = null;
  }
}

// 备选-回退的节点列表
function getBackNodeList(scope: any) {
  if (scope.row.sort < scope.row.backNodeId) {
    scope.row.backNodeId = undefined;
  }
  return formData.flowNodes.filter((n: FlowNodeVo, idx: number) => idx < scope.$index);
}

// 添加任务
function handleAddTask(scope: any) {
  formData.flowNodes.splice(scope.$index + 1, 0, cloneDeep(defaultNodeForm));
  handleFormatSort();
}

// 上移任务
function handleMoveUp(scope: any) {
  [formData.flowNodes[scope.$index - 1], formData.flowNodes[scope.$index]] = [
    formData.flowNodes[scope.$index],
    formData.flowNodes[scope.$index - 1],
  ];
  handleFormatSort();
}

// 下移任务
function handleMoveDown(scope: any) {
  [formData.flowNodes[scope.$index + 1], formData.flowNodes[scope.$index]] = [
    formData.flowNodes[scope.$index],
    formData.flowNodes[scope.$index + 1],
  ];
  handleFormatSort();
}

// 删除节点
function handleDelete(scope: any) {
  formData.flowNodes.splice(formData.flowNodes.indexOf(scope.row), 1);
  handleFormatSort();
}

// 处理sort顺序（包含回退sort）
function handleFormatSort() {
  formData.flowNodes.forEach((item, index) => {
    const nSort = index + 1;
    // 处理原sort
    const oBack = formData.flowNodes.find((n) => !n.isNewBackId && n.backNodeId === item.sort);
    if (oBack) {
      oBack.backNodeId = nSort;
      oBack.isNewBackId = true;
    }
    // 赋值新sort
    item.sort = nSort;
  });
  formData.flowNodes.forEach((f) => Reflect.deleteProperty(f, "isNewBackId"));
}

/**
 * 提交表单
 */
const handleSubmit = () => {
  flowFormRef.value.validate((valid: boolean) => {
    if (valid) {
      dialog.loading = true;
      if (formData.id) {
        FlowAPI.update(formData)
          .then(() => {
            ElMessage.success("修改流程模板成功");
            handleCloseDialog(formData.id);
          })
          .finally(() => (dialog.loading = false));
      } else {
        FlowAPI.create(formData)
          .then((d) => {
            ElMessage.success("新增流程模板成功");
            handleCloseDialog(d.id);
          })
          .finally(() => (dialog.loading = false));
      }
    }
  });
};

/**
 * 关闭弹窗
 */
function handleCloseDialog(id?: string) {
  flowFormRef.value.resetFields();
  flowFormRef.value.clearValidate();
  Object.assign(formData, cloneDeep(defaultForm));
  emits("dialogClose", id);
}
</script>

<style lang="scss" scoped></style>
